// This file is based on the MAME source code (see http://www.mame.net/)
// sources by Bryan McPhail,Fuzz,Ernesto Corvi,Andrew Prime,Zsolt Vasvari,IQ_132

/***************************************************************************

NeoGeo 'C' ROM encryption

Starting with KOF99, all NeoGeo games have encrypted graphics. Additionally
to that, the data for the front text layer, which was previously stored in
a separate ROM, is stored at the end of the tile data.

The encryption is one of the nastiest implementation of a XOR scheme ever
seen, involving 9 seemingly uncorrelated 256-byte tables. All known games use
the same tables except KOF2000 and MS4 which use a different set.

The 32 data bits of every longword are decrypted in a single step (one byte at
a time), but the values to use for the xor are determined in a convoluted way.
It's actually so convoluted that it's too difficult to describe - please refer
to the source below.
Suffice to say that bytes are handled in couples (0&3 and 1&2), and the two xor
values are taken from three tables, the indexes inside the tables depending on
bits 0-7 and 8-15 of the address, in one case further xored through the table
used in step 5) below. Additionally, the bytes in a couple can be swapped,
depending either on bit 8 of the address, or on bit 16 xored with the table
used in step 4) below.

The 24 address bits are encrypted in five steps. Each step xors 8 bits with a
value taken from a different table; the index inside the table depends on 8
other bits.
0) xor bits  0-7  with a fixed value that changes from game to game
1) xor bits  8-15 depending on bits 16-23
2) xor bits  8-15 depending on bits  0-7
3) xor bits 16-23 depending on bits  0-7
4) xor bits 16-23 depending on bits  8-15
5) xor bits  0-7  depending on bits  8-15

Each step acts on the current value, so e.g. step 4) uses bits 8-15 as modified
by step 2).

[Note: the table used in step 1) is currently incomplete due to lack of data to
analyze]


There are two major weaknesses in this encryption algorithm, that exposed it to
a known plaintext attack.

The first weakness is that the data xor depends on the address inside the
encrypted ROM instead that on the decrypted address; together with the high
concentration of 0x00 and 0xFF in the decrypted data (more than 60% of the
total), this exposed easily recognizable patterns in the encrypted data, which
could be exploited with some simple statistical checks. The deviousness of the
xor scheme was the major difficulty.

The second weakness is that the address scrambling works on 32-bit words. Since
there are a large number of 32-bit values that appear only once in the whole
encrypted ROM space, this means that once the xor layer was broken, a large
table of encrypted-decrypted address correspondencies could be built and
analyzed, quickly leading to the algorithm.

***************************************************************************/

#include "neogeo.h"
#include "bitswap.h"


const UINT8 *type0_t03;
const UINT8 *type0_t12;
const UINT8 *type1_t03;
const UINT8 *type1_t12;
const UINT8 *address_8_15_xor1;
const UINT8 *address_8_15_xor2;
const UINT8 *address_16_23_xor1;
const UINT8 *address_16_23_xor2;
const UINT8 *address_0_7_xor;


const UINT8 kof99_type0_t03[256] =
{
	0xfb, 0x86, 0x9d, 0xf1, 0xbf, 0x80, 0xd5, 0x43, 0xab, 0xb3, 0x9f, 0x6a, 0x33, 0xd9, 0xdb, 0xb6,
	0x66, 0x08, 0x69, 0x88, 0xcc, 0xb7, 0xde, 0x49, 0x97, 0x64, 0x1f, 0xa6, 0xc0, 0x2f, 0x52, 0x42,
	0x44, 0x5a, 0xf2, 0x28, 0x98, 0x87, 0x96, 0x8a, 0x83, 0x0b, 0x03, 0x61, 0x71, 0x99, 0x6b, 0xb5,
	0x1a, 0x8e, 0xfe, 0x04, 0xe1, 0xf7, 0x7d, 0xdd, 0xed, 0xca, 0x37, 0xfc, 0xef, 0x39, 0x72, 0xda,
	0xb8, 0xbe, 0xee, 0x7f, 0xe5, 0x31, 0x78, 0xf3, 0x91, 0x9a, 0xd2, 0x11, 0x19, 0xb9, 0x09, 0x4c,
	0xfd, 0x6d, 0x2a, 0x4d, 0x65, 0xa1, 0x89, 0xc7, 0x75, 0x50, 0x21, 0xfa, 0x16, 0x00, 0xe9, 0x12,
	0x74, 0x2b, 0x1e, 0x4f, 0x14, 0x01, 0x70, 0x3a, 0x4e, 0x3f, 0xf5, 0xf4, 0x1d, 0x3d, 0x15, 0x27,
	0xa7, 0xff, 0x45, 0xe0, 0x6e, 0xf9, 0x54, 0xc8, 0x48, 0xad, 0xa5, 0x0a, 0xf6, 0x2d, 0x2c, 0xe2,
	0x68, 0x67, 0xd6, 0x85, 0xb4, 0xc3, 0x34, 0xbc, 0x62, 0xd3, 0x5f, 0x84, 0x06, 0x5b, 0x0d, 0x95,
	0xea, 0x5e, 0x9e, 0xd4, 0xeb, 0x90, 0x7a, 0x05, 0x81, 0x57, 0xe8, 0x60, 0x2e, 0x20, 0x25, 0x7c,
	0x46, 0x0c, 0x93, 0xcb, 0xbd, 0x17, 0x7e, 0xec, 0x79, 0xb2, 0xc2, 0x22, 0x41, 0xb1, 0x10, 0xac,
	0xa8, 0xbb, 0x9b, 0x82, 0x4b, 0x9c, 0x8b, 0x07, 0x47, 0x35, 0x24, 0x56, 0x8d, 0xaf, 0xe6, 0x26,
	0x40, 0x38, 0xc4, 0x5d, 0x1b, 0xc5, 0xd1, 0x0f, 0x6c, 0x7b, 0xb0, 0xe3, 0xa3, 0x23, 0x6f, 0x58,
	0xc1, 0xba, 0xcf, 0xd7, 0xa2, 0xe7, 0xd0, 0x63, 0x5c, 0xf8, 0x73, 0xa0, 0x13, 0xdc, 0x29, 0xcd,
	0xc9, 0x76, 0xae, 0x8f, 0xe4, 0x59, 0x30, 0xaa, 0x94, 0x1c, 0x3c, 0x0e, 0x55, 0x92, 0x77, 0x32,
	0xc6, 0xce, 0x18, 0x36, 0xdf, 0xa9, 0x8c, 0xd8, 0xa4, 0xf0, 0x3b, 0x51, 0x4a, 0x02, 0x3e, 0x53,
};

const UINT8 kof99_type0_t12[256] =
{
	0x1f, 0xac, 0x4d, 0xcd, 0xca, 0x70, 0x02, 0x6b, 0x18, 0x40, 0x62, 0xb2, 0x3f, 0x9b, 0x5b, 0xef,
	0x69, 0x68, 0x71, 0x3b, 0xcb, 0xd4, 0x30, 0xbc, 0x47, 0x72, 0x74, 0x5e, 0x84, 0x4c, 0x1b, 0xdb,
	0x6a, 0x35, 0x1d, 0xf5, 0xa1, 0xb3, 0x87, 0x5d, 0x57, 0x28, 0x2f, 0xc4, 0xfd, 0x24, 0x26, 0x36,
	0xad, 0xbe, 0x61, 0x63, 0x73, 0xaa, 0x82, 0xee, 0x29, 0xd0, 0xdf, 0x8c, 0x15, 0xb5, 0x96, 0xf3,
	0xdd, 0x7e, 0x3a, 0x37, 0x58, 0x7f, 0x0c, 0xfc, 0x0b, 0x07, 0xe8, 0xf7, 0xf4, 0x14, 0xb8, 0x81,
	0xb6, 0xd7, 0x1e, 0xc8, 0x85, 0xe6, 0x9d, 0x33, 0x60, 0xc5, 0x95, 0xd5, 0x55, 0x00, 0xa3, 0xb7,
	0x7d, 0x50, 0x0d, 0xd2, 0xc1, 0x12, 0xe5, 0xed, 0xd8, 0xa4, 0x9c, 0x8f, 0x2a, 0x4f, 0xa8, 0x01,
	0x52, 0x83, 0x65, 0xea, 0x9a, 0x6c, 0x44, 0x4a, 0xe2, 0xa5, 0x2b, 0x46, 0xe1, 0x34, 0x25, 0xf8,
	0xc3, 0xda, 0xc7, 0x6e, 0x48, 0x38, 0x7c, 0x78, 0x06, 0x53, 0x64, 0x16, 0x98, 0x3c, 0x91, 0x42,
	0x39, 0xcc, 0xb0, 0xf1, 0xeb, 0x13, 0xbb, 0x05, 0x32, 0x86, 0x0e, 0xa2, 0x0a, 0x9e, 0xfa, 0x66,
	0x54, 0x8e, 0xd3, 0xe7, 0x19, 0x20, 0x77, 0xec, 0xff, 0xbd, 0x6d, 0x43, 0x23, 0x03, 0xab, 0x75,
	0x3d, 0xcf, 0xd1, 0xde, 0x92, 0x31, 0xa7, 0x45, 0x4b, 0xc2, 0x97, 0xf9, 0x7a, 0x88, 0xd9, 0x1c,
	0xe9, 0xe4, 0x10, 0xc9, 0x22, 0x2d, 0x90, 0x76, 0x17, 0x79, 0x04, 0x51, 0x1a, 0x5a, 0x5f, 0x2c,
	0x21, 0x6f, 0x3e, 0xe0, 0xf0, 0xbf, 0xd6, 0x94, 0x0f, 0x80, 0x11, 0xa0, 0x5c, 0xa9, 0x49, 0x2e,
	0xce, 0xaf, 0xa6, 0x9f, 0x7b, 0x99, 0xb9, 0xb4, 0xe3, 0xfb, 0xf6, 0x27, 0xf2, 0x93, 0xfe, 0x08,
	0x67, 0xae, 0x09, 0x89, 0xdc, 0x4e, 0xc6, 0xc0, 0x8a, 0xb1, 0x59, 0x8b, 0x41, 0x56, 0x8d, 0xba,
};

const UINT8 kof99_type1_t03[256] =
{
	0x0c, 0xe1, 0x8e, 0xeb, 0xac, 0xf8, 0xe2, 0xe4, 0xe8, 0x2d, 0x40, 0x63, 0x03, 0x39, 0xe6, 0xb2,
	0x4a, 0xfd, 0x61, 0xc1, 0xf3, 0x9e, 0x7d, 0x5b, 0xd3, 0x37, 0xb5, 0xb0, 0xf0, 0xc6, 0x8a, 0xc3,
	0x89, 0xa3, 0xd6, 0x3c, 0x72, 0x52, 0xdc, 0x06, 0x08, 0x77, 0xd0, 0x3e, 0x31, 0x05, 0xae, 0x8b,
	0x65, 0x0b, 0xa0, 0xc4, 0x12, 0x78, 0x8d, 0xde, 0x20, 0x60, 0x2b, 0x18, 0x28, 0xf2, 0xf7, 0x29,
	0x0a, 0xbe, 0x9c, 0x91, 0xbc, 0x94, 0xf5, 0x9f, 0xca, 0xc5, 0xb9, 0x86, 0x6c, 0x70, 0x6b, 0xdd,
	0x3f, 0xce, 0x0e, 0x47, 0xa1, 0x2c, 0x4d, 0xc7, 0x1a, 0x3d, 0xd7, 0x7a, 0xc9, 0x51, 0x62, 0x4f,
	0x25, 0x9a, 0x7e, 0xc8, 0x38, 0x4b, 0x83, 0xea, 0x0f, 0x1c, 0xbf, 0xb8, 0xb4, 0x43, 0x10, 0x81,
	0x88, 0xbd, 0x33, 0x75, 0x44, 0x2a, 0xcb, 0x2f, 0x02, 0x16, 0xfa, 0x22, 0xb3, 0xff, 0xa4, 0xdf,
	0xcc, 0x76, 0x30, 0x87, 0x49, 0xa7, 0x5a, 0xc0, 0x09, 0x01, 0xd1, 0x07, 0x5e, 0x3b, 0x19, 0xf1,
	0xa5, 0x8f, 0xf9, 0x74, 0x73, 0xcd, 0x5c, 0x54, 0x97, 0x69, 0x84, 0x4e, 0xba, 0xd2, 0x8c, 0x6d,
	0x48, 0x82, 0xfe, 0x11, 0x67, 0x1b, 0x27, 0x9b, 0xf6, 0x00, 0xfc, 0x41, 0xfb, 0xcf, 0x24, 0x50,
	0x9d, 0x90, 0x92, 0xda, 0x66, 0x6a, 0x56, 0xb7, 0x32, 0xc2, 0xec, 0x96, 0xd8, 0x15, 0x7c, 0xaa,
	0xed, 0x04, 0x45, 0x79, 0x85, 0xf4, 0x1d, 0x13, 0x2e, 0x1e, 0xd9, 0xbb, 0x23, 0xef, 0x36, 0x95,
	0x26, 0x98, 0xb1, 0xe3, 0xe5, 0xee, 0xad, 0xab, 0x93, 0xe0, 0x71, 0x7b, 0x21, 0x64, 0x1f, 0xa2,
	0x68, 0x4c, 0x6f, 0xd5, 0xe7, 0xa6, 0x46, 0x35, 0x59, 0x99, 0x80, 0x42, 0x5d, 0x57, 0x3a, 0xa8,
	0x14, 0xe9, 0x58, 0x7f, 0xd4, 0xdb, 0x55, 0x5f, 0x0d, 0xaf, 0x17, 0xa9, 0xb6, 0x53, 0x6e, 0x34,
};

const UINT8 kof99_type1_t12[256] =
{
	0x42, 0xb6, 0x9a, 0xef, 0x41, 0xf7, 0x3c, 0xfb, 0x1d, 0xfd, 0xd3, 0xd2, 0x7f, 0xa5, 0x3b, 0xf5,
	0x0d, 0x87, 0xa1, 0xb5, 0x80, 0x13, 0x92, 0x69, 0xb1, 0xc7, 0xd9, 0xc9, 0x5d, 0xd4, 0x99, 0xff,
	0x37, 0x93, 0xf1, 0x26, 0x20, 0xcd, 0x4a, 0xc6, 0x21, 0x39, 0x4c, 0xf4, 0x24, 0xc1, 0x84, 0xb2,
	0xe7, 0x6d, 0xf3, 0xe1, 0xd8, 0xd6, 0x28, 0xe9, 0xda, 0xad, 0x4b, 0x58, 0x23, 0x18, 0x10, 0xb9,
	0x5f, 0x2d, 0x2f, 0x56, 0x22, 0x81, 0x9f, 0x6f, 0x61, 0x07, 0xee, 0x3a, 0x7c, 0x5c, 0xfe, 0x4d,
	0xd7, 0xcf, 0xc8, 0x71, 0x32, 0xeb, 0xce, 0xe8, 0x74, 0x7a, 0x40, 0x1f, 0x1c, 0xdc, 0x8d, 0x0e,
	0xa0, 0x44, 0x7e, 0x72, 0x55, 0x68, 0x25, 0x73, 0x75, 0x9b, 0x70, 0xaf, 0x64, 0x6c, 0x49, 0x95,
	0x66, 0xdd, 0xde, 0x08, 0xa3, 0xcc, 0x51, 0x90, 0x9e, 0xa4, 0xab, 0xbf, 0x35, 0x19, 0x60, 0x48,
	0x8b, 0x16, 0x14, 0x38, 0xb0, 0x4f, 0xe4, 0x02, 0x2e, 0x6e, 0xf6, 0x85, 0x45, 0x31, 0x5a, 0xec,
	0x1e, 0x06, 0xaa, 0xf8, 0x78, 0x05, 0x7d, 0x83, 0x47, 0x8c, 0xc2, 0xbb, 0xc3, 0xb4, 0x6b, 0x88,
	0x7b, 0xa8, 0x89, 0x8f, 0x82, 0x27, 0xd5, 0xf9, 0x43, 0x00, 0x0c, 0x79, 0x33, 0x54, 0x3d, 0xdf,
	0x50, 0xbd, 0xdb, 0x65, 0x4e, 0x1a, 0x9d, 0xb3, 0xa2, 0xe0, 0xed, 0x63, 0xe5, 0xbe, 0x77, 0x86,
	0x1b, 0xa6, 0xc5, 0x98, 0x09, 0x12, 0x29, 0x96, 0x0f, 0xc0, 0x2c, 0xe3, 0xd0, 0x8a, 0x91, 0x46,
	0x6a, 0xf0, 0x3f, 0xd1, 0xa9, 0xcb, 0x2a, 0x9c, 0x01, 0x59, 0x5b, 0x3e, 0xb7, 0xba, 0xe2, 0x57,
	0x15, 0xfa, 0xca, 0xae, 0xc4, 0x17, 0x2b, 0x04, 0xb8, 0x94, 0xfc, 0x0a, 0xbc, 0x11, 0x36, 0x67,
	0x53, 0x52, 0x97, 0x30, 0x0b, 0x62, 0xf2, 0x76, 0xa7, 0x5e, 0xe6, 0xea, 0x03, 0x34, 0xac, 0x8e,
};



/* underlined values are wrong (not enough evidence, FF fill in kof99 and garou) */
/* they correspond to tiles 7d000-7efff */
const UINT8 kof99_address_8_15_xor1[256] =
{
	0x00, 0xb1, 0x1e, 0xc5, 0x3d, 0x40, 0x45, 0x5e, 0xf2, 0xf8, 0x04, 0x63, 0x36, 0x87, 0x88, 0xbf,
	0xab, 0xcc, 0x78, 0x08, 0xdd, 0x20, 0xd4, 0x35, 0x09, 0x8e, 0x44, 0xae, 0x33, 0xa9, 0x9e, 0xcd,
	0xb3, 0xe5, 0xad, 0x41, 0xda, 0xbe, 0xf4, 0x16, 0x57, 0x2e, 0x53, 0x67, 0xaf, 0xdb, 0x8a, 0xd8,
	0x34, 0x17, 0x3c, 0x01, 0x55, 0x73, 0xcf, 0xe3, 0xe8, 0xc7, 0x0d, 0xe9, 0xa3, 0x13, 0x0c, 0xf6,
	0x90, 0x4e, 0xfb, 0x97, 0x6d, 0x5f, 0xa8, 0x71, 0x11, 0xfc, 0xd1, 0x95, 0x81, 0xba, 0x8c, 0x1b,
	0x39, 0xfe, 0xa2, 0x15, 0xa6, 0x52, 0x4d, 0x5b, 0x59, 0xa5, 0xe0, 0x96, 0xd9, 0x8f, 0x7b, 0xed,
	0x29, 0xd3, 0x1f, 0x0e, 0xec, 0x23, 0x0f, 0xb8, 0x6c, 0x6f, 0x7d, 0x18, 0x46, 0xd6, 0xe4, 0xb5,
	0x9a, 0x79, 0x02, 0xf5, 0x03, 0xc0, 0x60, 0x66, 0x5c, 0x2f, 0x76, 0x85, 0x9d, 0x54, 0x1a, 0x6a,
	0x28, 0xce, 0x7f, 0x7c, 0x91, 0x99, 0x4c, 0x83, 0x3e, 0xb4, 0x1d, 0x05, 0xc1, 0xc3, 0xd7, 0x47,
	0xde, 0xbc, 0x62, 0x6e, 0x86, 0x14, 0x80, 0x77, 0xeb, 0xf3, 0x07, 0x31, 0x56, 0xd2, 0xc2, 0xc6,
	0x6b, 0xdc, 0xfd, 0x22, 0x92, 0xf0, 0x06, 0x51, 0x2d, 0x38, 0xe6, 0xa0, 0x25, 0xdf, 0xd5, 0x2c,
	0x1c, 0x94, 0x12, 0x9c, 0xb0, 0x9b, 0xc4, 0x0b, 0xc8, 0xd0, 0xf7, 0x30, 0xcb, 0x27, 0xfa, 0x7a,
	0x10, 0x61, 0xaa, 0xa4, 0x70, 0xb7, 0x2a, 0x5a, 0xc9, 0xf1, 0x0a, 0x49, 0x65, 0xee, 0x69, 0x4b,
	0x3a, 0x8d, 0x32, 0x5d, 0x68, 0xb9, 0x9f, 0x75, 0x19, 0x3f, 0xac, 0x37, 0x4f, 0xe7, 0x93, 0x89,
	0x7e, 0x4a, 0x3b, 0xea, 0x74, 0x72, 0x43, 0xbd, 0x24, 0xef, 0xb6, 0xff, 0x64, 0x58, 0x84, 0x8b,
	0xa7, 0xbb, 0xb2, 0xe1, 0x26, 0x2b, 0x50, 0xca, 0x21, 0xf9, 0x98, 0xa1, 0xe2, 0x42, 0x82, 0x48,
//	                                                            ^^^^  ^^^^  ^^^^  ^^^^
};

const UINT8 kof99_address_8_15_xor2[256] =
{
	0xcf, 0xb5, 0xa3, 0x19, 0x4e, 0x15, 0xf0, 0x13, 0x60, 0x10, 0x07, 0x87, 0x51, 0x3c, 0x73, 0x14,
	0x68, 0x2d, 0x3e, 0x34, 0xae, 0x67, 0xa7, 0x5a, 0x36, 0x0d, 0x02, 0x0a, 0x40, 0x84, 0x22, 0x11,
	0x75, 0x27, 0x16, 0xfd, 0xfe, 0x08, 0xcb, 0x8d, 0x7e, 0x72, 0xc8, 0x94, 0xfc, 0x0e, 0xac, 0xb7,
	0x1d, 0x58, 0x17, 0x1e, 0x82, 0x85, 0xfa, 0x1a, 0x83, 0x38, 0x4b, 0xc2, 0x7f, 0xe2, 0xe6, 0x32,
	0x41, 0x78, 0x79, 0xc5, 0xff, 0x2e, 0x21, 0x59, 0x5e, 0x6d, 0x99, 0xf3, 0xd0, 0xc0, 0x91, 0x48,
	0x05, 0x09, 0x8a, 0x56, 0xf7, 0x1b, 0x89, 0x9a, 0xd4, 0xd3, 0xce, 0x61, 0xe0, 0x80, 0x28, 0xe9,
	0xbe, 0xcc, 0xd1, 0xd7, 0x44, 0xda, 0x7c, 0x57, 0x54, 0x23, 0xd6, 0x39, 0xdc, 0xd8, 0x4a, 0x24,
	0xdd, 0x00, 0x81, 0xea, 0x3f, 0x88, 0x46, 0xa6, 0xa1, 0xbc, 0x3b, 0x31, 0x74, 0x62, 0xde, 0xca,
	0x2b, 0xe5, 0xe4, 0xf2, 0xb6, 0x49, 0x9c, 0xef, 0xf9, 0xd9, 0x95, 0x2c, 0x4c, 0x76, 0xc3, 0x98,
	0xe1, 0xed, 0xbb, 0x92, 0xd2, 0x6c, 0x50, 0x2f, 0x4d, 0xa8, 0x8f, 0x33, 0x0f, 0xb4, 0x5b, 0xaa,
	0x53, 0xba, 0x2a, 0x29, 0xaf, 0x7d, 0x04, 0x12, 0x4f, 0xee, 0xe8, 0x52, 0x77, 0xc4, 0x70, 0x01,
	0xc6, 0x30, 0x03, 0x5c, 0xc9, 0xe3, 0x20, 0x37, 0xbf, 0x9e, 0x18, 0x5f, 0x1c, 0xb1, 0x55, 0xad,
	0x63, 0xbd, 0x0c, 0xa2, 0x6a, 0xe7, 0x7a, 0xa5, 0x69, 0x8e, 0xf8, 0x1f, 0x86, 0xab, 0x26, 0xcd,
	0xdb, 0x96, 0x71, 0x06, 0x3a, 0x0b, 0xfb, 0xa0, 0x6e, 0x42, 0x43, 0xf1, 0x35, 0xb3, 0x9f, 0x45,
	0x64, 0x93, 0x8b, 0xb9, 0x8c, 0x65, 0x7b, 0xec, 0xb2, 0xa4, 0x90, 0xeb, 0xb0, 0x66, 0xf5, 0x5d,
	0x47, 0xc7, 0x25, 0xf6, 0x6b, 0xdf, 0x97, 0xd5, 0x3d, 0xc1, 0x9d, 0x9b, 0x6f, 0xf4, 0xb8, 0xa9,
};

const UINT8 kof99_address_16_23_xor1[256] =
{
	0xd2, 0x24, 0x93, 0x21, 0x82, 0xa8, 0xa5, 0xa6, 0xa0, 0x42, 0xf4, 0x65, 0x55, 0x48, 0xa7, 0x8d,
	0xf1, 0x2a, 0x64, 0x34, 0x2d, 0x9b, 0x6a, 0x79, 0x3d, 0x4f, 0x0e, 0x8c, 0xac, 0xb7, 0x91, 0x35,
	0x10, 0x05, 0xbf, 0xca, 0xed, 0xfd, 0xba, 0xd7, 0xd0, 0x6f, 0xbc, 0xcb, 0x4c, 0x56, 0x83, 0x11,
	0x66, 0x51, 0x84, 0xb6, 0xdd, 0xe8, 0x12, 0xbb, 0xc4, 0xe4, 0x41, 0xd8, 0xc0, 0xad, 0x2f, 0x40,
	0xd1, 0x8b, 0x9a, 0x1c, 0x8a, 0x9e, 0x2e, 0x1b, 0xb1, 0x36, 0x08, 0x97, 0xe2, 0xec, 0x61, 0x3a,
	0x4b, 0xb3, 0xd3, 0x77, 0x04, 0xc2, 0x72, 0x37, 0xd9, 0x4a, 0x3f, 0xe9, 0x30, 0x7c, 0xe5, 0x73,
	0x46, 0x99, 0xeb, 0xb0, 0xc8, 0x71, 0x15, 0xa1, 0x53, 0xda, 0x0b, 0x88, 0x8e, 0x75, 0xdc, 0x14,
	0x90, 0x0a, 0x4d, 0x6e, 0xf6, 0xc1, 0x31, 0x43, 0xd5, 0xdf, 0xa9, 0xc5, 0x0d, 0x2b, 0x86, 0x3b,
	0xb2, 0xef, 0xcc, 0x17, 0x70, 0x07, 0xf9, 0xb4, 0x50, 0x54, 0x3c, 0x57, 0xfb, 0x49, 0x58, 0x2c,
	0x06, 0x13, 0x28, 0xee, 0x6d, 0x32, 0xfa, 0xfe, 0x1f, 0x60, 0x96, 0xf3, 0x89, 0xbd, 0x92, 0x62,
	0xf0, 0x95, 0xab, 0x5c, 0x67, 0x59, 0x47, 0x19, 0xaf, 0xd4, 0xaa, 0x74, 0x29, 0x33, 0xc6, 0xfc,
	0x1a, 0x9c, 0x9d, 0xb9, 0xe7, 0xe1, 0xff, 0x0f, 0xcd, 0xb5, 0xa2, 0x9f, 0xb8, 0x5e, 0xea, 0x81,
	0x22, 0xd6, 0x76, 0x68, 0x16, 0xae, 0x5a, 0x5d, 0xc3, 0xdb, 0x38, 0x09, 0x45, 0x23, 0xcf, 0x1e,
	0xc7, 0x98, 0x0c, 0x25, 0x26, 0xa3, 0x02, 0x01, 0x1d, 0xa4, 0x6c, 0x69, 0x44, 0xe6, 0x5b, 0x85,
	0xe0, 0xf2, 0x63, 0x3e, 0x27, 0x87, 0xf7, 0x4e, 0x78, 0x18, 0x94, 0xf5, 0x7a, 0x7f, 0xc9, 0x80,
	0xde, 0x20, 0xf8, 0x6b, 0xbe, 0x39, 0x7e, 0x7b, 0x52, 0x03, 0x5f, 0x00, 0x8f, 0x7d, 0xe3, 0xce,
};

const UINT8 kof99_address_16_23_xor2[256] =
{
	0x29, 0x97, 0x1a, 0x2c, 0x0b, 0x94, 0x3e, 0x75, 0x01, 0x0d, 0x1b, 0xe1, 0x4d, 0x38, 0x39, 0x8f,
	0xe7, 0xd0, 0x60, 0x90, 0xb2, 0x0f, 0xbb, 0x70, 0x1f, 0xe6, 0x5b, 0x87, 0xb4, 0x43, 0xfd, 0xf5,
	0xf6, 0xf9, 0xad, 0xc0, 0x98, 0x17, 0x9f, 0x91, 0x15, 0x51, 0x55, 0x64, 0x6c, 0x18, 0x61, 0x0e,
	0xd9, 0x93, 0xab, 0xd6, 0x24, 0x2f, 0x6a, 0x3a, 0x22, 0xb1, 0x4f, 0xaa, 0x23, 0x48, 0xed, 0xb9,
	0x88, 0x8b, 0xa3, 0x6b, 0x26, 0x4c, 0xe8, 0x2d, 0x1c, 0x99, 0xbd, 0x5c, 0x58, 0x08, 0x50, 0xf2,
	0x2a, 0x62, 0xc1, 0x72, 0x66, 0x04, 0x10, 0x37, 0x6e, 0xfc, 0x44, 0xa9, 0xdf, 0xd4, 0x20, 0xdd,
	0xee, 0x41, 0xdb, 0x73, 0xde, 0x54, 0xec, 0xc9, 0xf3, 0x4b, 0x2e, 0xae, 0x5a, 0x4a, 0x5e, 0x47,
	0x07, 0x2b, 0x76, 0xa4, 0xe3, 0x28, 0xfe, 0xb0, 0xf0, 0x02, 0x06, 0xd1, 0xaf, 0x42, 0xc2, 0xa5,
	0xe0, 0x67, 0xbf, 0x16, 0x8e, 0x35, 0xce, 0x8a, 0xe5, 0x3d, 0x7b, 0x96, 0xd7, 0x79, 0x52, 0x1e,
	0xa1, 0xfb, 0x9b, 0xbe, 0x21, 0x9c, 0xe9, 0x56, 0x14, 0x7f, 0xa0, 0xe4, 0xc3, 0xc4, 0x46, 0xea,
	0xf7, 0xd2, 0x1d, 0x31, 0x0a, 0x5f, 0xeb, 0xa2, 0x68, 0x8d, 0xb5, 0xc5, 0x74, 0x0c, 0xdc, 0x82,
	0x80, 0x09, 0x19, 0x95, 0x71, 0x9a, 0x11, 0x57, 0x77, 0x4e, 0xc6, 0xff, 0x12, 0x03, 0xa7, 0xc7,
	0xf4, 0xc8, 0xb6, 0x7a, 0x59, 0x36, 0x3c, 0x53, 0xe2, 0x69, 0x8c, 0x25, 0x05, 0x45, 0x63, 0xf8,
	0x34, 0x89, 0x33, 0x3f, 0x85, 0x27, 0xbc, 0x65, 0xfa, 0xa8, 0x6d, 0x84, 0x5d, 0xba, 0x40, 0x32,
	0x30, 0xef, 0x83, 0x13, 0xa6, 0x78, 0xcc, 0x81, 0x9e, 0xda, 0xca, 0xd3, 0x7e, 0x9d, 0x6f, 0xcd,
	0xb7, 0xb3, 0xd8, 0xcf, 0x3b, 0x00, 0x92, 0xb8, 0x86, 0xac, 0x49, 0x7c, 0xf1, 0xd5, 0xcb, 0x7d,
};

const UINT8 kof99_address_0_7_xor[256] =
{
	0x8f, 0x56, 0xa6, 0xe6, 0x65, 0x38, 0x01, 0xb5, 0x0c, 0x20, 0x31, 0x59, 0x9f, 0xcd, 0xad, 0xf7,
	0xb4, 0x34, 0xb8, 0x9d, 0xe5, 0x6a, 0x18, 0x5e, 0xa3, 0x39, 0x3a, 0x2f, 0x42, 0x26, 0x8d, 0xed,
	0x35, 0x9a, 0x8e, 0xfa, 0xd0, 0xd9, 0xc3, 0xae, 0xab, 0x14, 0x97, 0x62, 0xfe, 0x12, 0x13, 0x1b,
	0xd6, 0x5f, 0xb0, 0xb1, 0xb9, 0x55, 0x41, 0x77, 0x94, 0x68, 0xef, 0x46, 0x8a, 0xda, 0x4b, 0xf9,
	0xee, 0x3f, 0x1d, 0x9b, 0x2c, 0xbf, 0x06, 0x7e, 0x85, 0x83, 0x74, 0xfb, 0x7a, 0x0a, 0x5c, 0xc0,
	0x5b, 0xeb, 0x0f, 0x64, 0xc2, 0x73, 0xce, 0x99, 0x30, 0xe2, 0xca, 0xea, 0xaa, 0x00, 0xd1, 0xdb,
	0xbe, 0x28, 0x86, 0x69, 0xe0, 0x09, 0xf2, 0xf6, 0x6c, 0x52, 0x4e, 0xc7, 0x15, 0xa7, 0x54, 0x80,
	0x29, 0xc1, 0xb2, 0x75, 0x4d, 0x36, 0x22, 0x25, 0x71, 0xd2, 0x95, 0x23, 0xf0, 0x1a, 0x92, 0x7c,
	0xe1, 0x6d, 0xe3, 0x37, 0x24, 0x1c, 0x3e, 0x3c, 0x03, 0xa9, 0x32, 0x0b, 0x4c, 0x1e, 0xc8, 0x21,
	0x9c, 0x66, 0x58, 0xf8, 0xf5, 0x89, 0xdd, 0x82, 0x19, 0x43, 0x07, 0x51, 0x05, 0x4f, 0x7d, 0x33,
	0x2a, 0x47, 0xe9, 0xf3, 0x8c, 0x10, 0xbb, 0x76, 0xff, 0xde, 0xb6, 0xa1, 0x91, 0x81, 0xd5, 0xba,
	0x9e, 0xe7, 0xe8, 0x6f, 0x49, 0x98, 0xd3, 0xa2, 0xa5, 0x61, 0xcb, 0xfc, 0x3d, 0x44, 0xec, 0x0e,
	0xf4, 0x72, 0x08, 0xe4, 0x11, 0x96, 0x48, 0x3b, 0x8b, 0xbc, 0x02, 0xa8, 0x0d, 0x2d, 0xaf, 0x16,
	0x90, 0xb7, 0x1f, 0x70, 0x78, 0xdf, 0x6b, 0x4a, 0x87, 0x40, 0x88, 0x50, 0x2e, 0xd4, 0xa4, 0x17,
	0x67, 0xd7, 0x53, 0xcf, 0xbd, 0xcc, 0xdc, 0x5a, 0xf1, 0xfd, 0x7b, 0x93, 0x79, 0xc9, 0x7f, 0x04,
	0xb3, 0x57, 0x84, 0xc4, 0x6e, 0x27, 0x63, 0x60, 0x45, 0xd8, 0xac, 0xc5, 0xa0, 0x2b, 0xc6, 0x5d,
};






const UINT8 kof2000_type0_t03[256] =
{
	0x10, 0x61, 0xf1, 0x78, 0x85, 0x52, 0x68, 0xe3, 0x12, 0x0d, 0xfa, 0xf0, 0xc9, 0x36, 0x5e, 0x3d,
	0xf9, 0xa6, 0x01, 0x2e, 0xc7, 0x84, 0xea, 0x2b, 0x6d, 0x14, 0x38, 0x4f, 0x55, 0x1c, 0x9d, 0xa7,
	0x7a, 0xc6, 0xf8, 0x9a, 0xe6, 0x42, 0xb5, 0xed, 0x7d, 0x3a, 0xb1, 0x05, 0x43, 0x4a, 0x22, 0xfd,
	0xac, 0xa4, 0x31, 0xc3, 0x32, 0x76, 0x95, 0x9e, 0x7e, 0x88, 0x8e, 0xa2, 0x97, 0x18, 0xbe, 0x2a,
	0xf5, 0xd6, 0xca, 0xcc, 0x72, 0x3b, 0x87, 0x6c, 0xde, 0x75, 0xd7, 0x21, 0xcb, 0x0b, 0xdd, 0xe7,
	0xe1, 0x65, 0xaa, 0xb9, 0x44, 0xfb, 0x66, 0x15, 0x1a, 0x3c, 0x98, 0xcf, 0x8a, 0xdf, 0x37, 0xa5,
	0x2f, 0x67, 0xd2, 0x83, 0xb6, 0x6b, 0xfc, 0xe0, 0xb4, 0x7c, 0x08, 0xdc, 0x93, 0x30, 0xab, 0xe4,
	0x19, 0xc2, 0x8b, 0xeb, 0xa0, 0x0a, 0xc8, 0x03, 0xc0, 0x4b, 0x64, 0x71, 0x86, 0x9c, 0x9b, 0x16,
	0x79, 0xff, 0x70, 0x09, 0x8c, 0xd0, 0xf6, 0x53, 0x07, 0x73, 0xd4, 0x89, 0xb3, 0x00, 0xe9, 0xfe,
	0xec, 0x8f, 0xbc, 0xb2, 0x1e, 0x5d, 0x11, 0x35, 0xa9, 0x06, 0x59, 0x9f, 0xc1, 0xd3, 0x7b, 0xf2,
	0xc5, 0x77, 0x4e, 0x39, 0x20, 0xd5, 0x6a, 0x82, 0xda, 0x45, 0xf3, 0x33, 0x81, 0x23, 0xba, 0xe2,
	0x1d, 0x5f, 0x5c, 0x51, 0x49, 0xae, 0x8d, 0xc4, 0xa8, 0xf7, 0x1f, 0x0f, 0x34, 0x28, 0xa1, 0xd9,
	0x27, 0xd8, 0x4c, 0x2c, 0xbf, 0x91, 0x3e, 0x69, 0x57, 0x41, 0x25, 0x0c, 0x5a, 0x90, 0x92, 0xb0,
	0x63, 0x6f, 0x40, 0xaf, 0x74, 0xb8, 0x2d, 0x80, 0xbb, 0x46, 0x94, 0xe5, 0x29, 0xee, 0xb7, 0x1b,
	0x96, 0xad, 0x13, 0x0e, 0x58, 0x99, 0x60, 0x4d, 0x17, 0x26, 0xce, 0xe8, 0xdb, 0xef, 0x24, 0xa3,
	0x6e, 0x7f, 0x54, 0x3f, 0x02, 0xd1, 0x5b, 0x50, 0x56, 0x48, 0xf4, 0xbd, 0x62, 0x47, 0x04, 0xcd,
};

const UINT8 kof2000_type0_t12[256] =
{
	0xf4, 0x28, 0xb4, 0x8f, 0xfa, 0xeb, 0x8e, 0x54, 0x2b, 0x49, 0xd1, 0x76, 0x71, 0x47, 0x8b, 0x57,
	0x92, 0x85, 0x7c, 0xb8, 0x5c, 0x22, 0xf9, 0x26, 0xbc, 0x5b, 0x6d, 0x67, 0xae, 0x5f, 0x6f, 0xf5,
	0x9f, 0x48, 0x66, 0x40, 0x0d, 0x11, 0x4e, 0xb2, 0x6b, 0x35, 0x15, 0x0f, 0x18, 0x25, 0x1d, 0xba,
	0xd3, 0x69, 0x79, 0xec, 0xa8, 0x8c, 0xc9, 0x7f, 0x4b, 0xdb, 0x51, 0xaf, 0xca, 0xe2, 0xb3, 0x81,
	0x12, 0x5e, 0x7e, 0x38, 0xc8, 0x95, 0x01, 0xff, 0xfd, 0xfb, 0xf2, 0x74, 0x62, 0x14, 0xa5, 0x98,
	0xa6, 0xda, 0x80, 0x53, 0xe8, 0x56, 0xac, 0x1b, 0x52, 0xd0, 0xf1, 0x45, 0x42, 0xb6, 0x1a, 0x4a,
	0x3a, 0x99, 0xfc, 0xd2, 0x9c, 0xcf, 0x31, 0x2d, 0xdd, 0x86, 0x2f, 0x29, 0xe1, 0x03, 0x19, 0xa2,
	0x41, 0x33, 0x83, 0x90, 0xc1, 0xbf, 0x0b, 0x08, 0x3d, 0xd8, 0x8d, 0x6c, 0x39, 0xa0, 0xe3, 0x55,
	0x02, 0x50, 0x46, 0xe6, 0xc3, 0x82, 0x36, 0x13, 0x75, 0xab, 0x27, 0xd7, 0x1f, 0x0a, 0xd4, 0x89,
	0x59, 0x4f, 0xc0, 0x5d, 0xc6, 0xf7, 0x88, 0xbd, 0x3c, 0x00, 0xef, 0xcd, 0x05, 0x1c, 0xaa, 0x9b,
	0xed, 0x7a, 0x61, 0x17, 0x93, 0xfe, 0x23, 0xb9, 0xf3, 0x68, 0x78, 0xf6, 0x5a, 0x7b, 0xe0, 0xe4,
	0xa3, 0xee, 0x16, 0x72, 0xc7, 0x3b, 0x8a, 0x37, 0x2a, 0x70, 0xa9, 0x2c, 0x21, 0xf8, 0x24, 0x09,
	0xce, 0x20, 0x9e, 0x06, 0x87, 0xc5, 0x04, 0x64, 0x43, 0x7d, 0x4d, 0x10, 0xd6, 0xa4, 0x94, 0x4c,
	0x60, 0xde, 0xdf, 0x58, 0xb1, 0x44, 0x3f, 0xb0, 0xd9, 0xe5, 0xcb, 0xbb, 0xbe, 0xea, 0x07, 0x34,
	0x73, 0x6a, 0x77, 0xf0, 0x9d, 0x0c, 0x2e, 0x0e, 0x91, 0x9a, 0xcc, 0xc2, 0xb7, 0x63, 0x97, 0xd5,
	0xdc, 0xc4, 0x32, 0xe7, 0x84, 0x3e, 0x30, 0xa1, 0x1e, 0xb5, 0x6e, 0x65, 0xe9, 0xad, 0xa7, 0x96,
};

const UINT8 kof2000_type1_t03[256] =
{
	0x5b, 0x34, 0x0c, 0xb8, 0x24, 0xe7, 0x2b, 0x05, 0x97, 0xb1, 0xa4, 0xa7, 0xc3, 0x57, 0x1b, 0xe0,
	0x73, 0xed, 0x94, 0xf7, 0x06, 0x46, 0xd5, 0xf1, 0x9c, 0x1e, 0x11, 0xa0, 0x48, 0x45, 0xf0, 0x6a,
	0x81, 0x6d, 0xa8, 0x59, 0xc1, 0x13, 0xb0, 0x9e, 0xc6, 0x67, 0x41, 0x89, 0x9d, 0x82, 0xd4, 0x7d,
	0x90, 0xdb, 0x2d, 0x54, 0x14, 0x29, 0x84, 0x58, 0x5a, 0xa6, 0x86, 0x3e, 0x0f, 0x9b, 0xc8, 0x4d,
	0x23, 0x31, 0x33, 0xe9, 0xda, 0xbf, 0xf5, 0x37, 0x09, 0x5e, 0x38, 0xc7, 0xcd, 0x8b, 0x0b, 0x80,
	0x91, 0x0d, 0x55, 0x74, 0xa5, 0x7b, 0x0a, 0x61, 0x40, 0x69, 0xac, 0xca, 0x9a, 0x2f, 0xcc, 0x4e,
	0x16, 0xa1, 0x1d, 0xa9, 0x5f, 0x07, 0x5d, 0x6f, 0xb5, 0x92, 0x51, 0xec, 0x8c, 0x7c, 0xaa, 0x98,
	0x01, 0xe2, 0xf6, 0x47, 0x76, 0x62, 0x9f, 0x2e, 0x6e, 0x5c, 0xad, 0xf4, 0xae, 0x87, 0xe5, 0xfa,
	0x1f, 0x56, 0xd6, 0xe8, 0x88, 0x18, 0x19, 0x68, 0x1c, 0xfc, 0x77, 0x1a, 0xd1, 0x8d, 0xe3, 0xbb,
	0x3f, 0x3b, 0x7f, 0x66, 0xab, 0x42, 0x95, 0xe1, 0xde, 0x7a, 0x65, 0xd2, 0x28, 0x6c, 0x0e, 0x04,
	0x71, 0xcf, 0x10, 0xbe, 0x99, 0x63, 0xba, 0xb2, 0x60, 0x50, 0xeb, 0x4b, 0xaf, 0x17, 0xf8, 0xfb,
	0x30, 0xef, 0x96, 0x4c, 0x44, 0xdc, 0xf3, 0x32, 0x3d, 0x26, 0xb3, 0xc9, 0xb6, 0xbc, 0xd3, 0xea,
	0x27, 0xee, 0x43, 0xfe, 0x00, 0xd7, 0x75, 0x8a, 0xce, 0x3c, 0x21, 0x2c, 0x52, 0xc2, 0x22, 0x2a,
	0x7e, 0x36, 0x4a, 0x4f, 0xe4, 0x53, 0xc5, 0x72, 0x25, 0x8f, 0xd9, 0xa2, 0xbd, 0x39, 0x8e, 0xe6,
	0x35, 0xff, 0x70, 0xdd, 0xdf, 0x15, 0x93, 0x08, 0x03, 0xb4, 0xc0, 0xf2, 0x79, 0x64, 0x3a, 0x49,
	0x12, 0xf9, 0xfd, 0xd8, 0x20, 0xd0, 0x83, 0xc4, 0x78, 0xb7, 0x85, 0x02, 0xcb, 0x6b, 0xb9, 0xa3,
};

const UINT8 kof2000_type1_t12[256] =
{
	0xb5, 0x50, 0xdf, 0x66, 0x9d, 0x8d, 0x2b, 0x56, 0x98, 0xa1, 0xad, 0xe4, 0x1d, 0x7e, 0x88, 0x3b,
	0x8e, 0xef, 0x80, 0xcd, 0xc0, 0x4f, 0x0c, 0x42, 0xf3, 0x43, 0xaf, 0x9c, 0xe6, 0x52, 0xd7, 0x8c,
	0x69, 0xf7, 0xbc, 0x34, 0xf2, 0x3d, 0x9a, 0xb0, 0xb2, 0x4e, 0xc3, 0x59, 0x82, 0x9e, 0xcf, 0x26,
	0x89, 0xa8, 0x39, 0xea, 0xf9, 0xfe, 0x73, 0x07, 0xe1, 0xee, 0x4a, 0x47, 0x6d, 0xd4, 0x60, 0x09,
	0xed, 0x1b, 0x65, 0xe7, 0xd0, 0x38, 0xca, 0x06, 0x3c, 0x61, 0x96, 0x11, 0xbe, 0xeb, 0x9f, 0xd5,
	0x46, 0x2a, 0xac, 0xc9, 0xa4, 0xce, 0xd3, 0xfd, 0x2f, 0x5e, 0xf0, 0x3f, 0xda, 0xa7, 0xd6, 0x6e,
	0x14, 0x35, 0x72, 0xff, 0xb6, 0xcc, 0xb1, 0x5f, 0x92, 0x58, 0x0a, 0x7b, 0xbb, 0x54, 0xe3, 0x2e,
	0x01, 0xa9, 0xa6, 0xfc, 0x95, 0x00, 0xec, 0xf1, 0xbf, 0x5b, 0x5d, 0xa5, 0x23, 0xdd, 0xd9, 0x05,
	0xb3, 0xab, 0x9b, 0x87, 0x0b, 0x18, 0x63, 0x7f, 0x51, 0x40, 0x31, 0xa2, 0xcb, 0xf5, 0x7d, 0x37,
	0xb8, 0xf8, 0xba, 0x2d, 0x0e, 0xdc, 0xd2, 0x79, 0xb4, 0x91, 0x8a, 0x13, 0x0d, 0xe2, 0xd8, 0x10,
	0x74, 0x1e, 0x21, 0x6a, 0x6f, 0x32, 0xb7, 0x3e, 0xc1, 0x44, 0x17, 0x12, 0x1f, 0x49, 0x8f, 0x4c,
	0x03, 0x75, 0x15, 0x7a, 0x85, 0x68, 0x33, 0x19, 0x27, 0x45, 0x7c, 0x1c, 0xf6, 0x90, 0xde, 0xc8,
	0x02, 0x5a, 0x41, 0x5c, 0x84, 0x67, 0x1a, 0x70, 0xb9, 0x86, 0x6b, 0xa3, 0x76, 0x97, 0xa0, 0xe0,
	0xbd, 0xf4, 0x77, 0xe9, 0x83, 0x30, 0x55, 0xc2, 0x57, 0x71, 0x99, 0x6c, 0xe5, 0x36, 0x22, 0xfb,
	0x48, 0xd1, 0x08, 0x24, 0x04, 0xc5, 0xfa, 0x29, 0x62, 0xe8, 0xc4, 0xdb, 0x94, 0x2c, 0x3a, 0xc7,
	0x20, 0x93, 0xae, 0x0f, 0x53, 0x16, 0x4d, 0x8b, 0x78, 0x4b, 0xc6, 0x64, 0x25, 0x81, 0xaa, 0x28,
};



const UINT8 kof2000_address_8_15_xor1[256] =
{
	0xfc, 0x9b, 0x1c, 0x35, 0x72, 0x53, 0xd6, 0x7d, 0x84, 0xa4, 0xc5, 0x93, 0x7b, 0xe7, 0x47, 0xd5,
	0x24, 0xa2, 0xfa, 0x19, 0x0c, 0xb1, 0x8c, 0xb9, 0x9d, 0xd8, 0x59, 0x4f, 0x3c, 0xb2, 0x78, 0x4a,
	0x2a, 0x96, 0x9a, 0xf1, 0x1f, 0x22, 0xa8, 0x5b, 0x67, 0xa3, 0x0f, 0x00, 0xfb, 0xdf, 0xeb, 0x0a,
	0x57, 0xb8, 0x25, 0xd7, 0xf0, 0x6b, 0x0b, 0x31, 0x95, 0x23, 0x2d, 0x5c, 0x27, 0xc7, 0xf4, 0x55,
	0x1a, 0xf7, 0x74, 0xbe, 0xd3, 0xac, 0x3d, 0xc1, 0x7f, 0xbd, 0x28, 0x01, 0x10, 0xe5, 0x09, 0x37,
	0x1e, 0x58, 0xaf, 0x17, 0xf2, 0x16, 0x30, 0x92, 0x36, 0x68, 0xe6, 0xd4, 0xea, 0xb7, 0x75, 0x54,
	0x77, 0x41, 0xb4, 0x8d, 0xe0, 0xf3, 0x51, 0x03, 0xa9, 0xe8, 0x66, 0xab, 0x29, 0xa5, 0xed, 0xcb,
	0xd1, 0xaa, 0xf5, 0xdb, 0x4c, 0x42, 0x97, 0x8a, 0xae, 0xc9, 0x6e, 0x04, 0x33, 0x85, 0xdd, 0x2b,
	0x6f, 0xef, 0x12, 0x21, 0x7a, 0xa1, 0x5a, 0x91, 0xc8, 0xcc, 0xc0, 0xa7, 0x60, 0x3e, 0x56, 0x2f,
	0xe4, 0x71, 0x99, 0xc2, 0xa0, 0x45, 0x80, 0x65, 0xbb, 0x87, 0x69, 0x81, 0x73, 0xca, 0xf6, 0x46,
	0x43, 0xda, 0x26, 0x7e, 0x8f, 0xe1, 0x8b, 0xfd, 0x50, 0x79, 0xba, 0xc6, 0x63, 0x4b, 0xb3, 0x8e,
	0x34, 0xe2, 0x48, 0x14, 0xcd, 0xe3, 0xc4, 0x05, 0x13, 0x40, 0x06, 0x6c, 0x88, 0xb0, 0xe9, 0x1b,
	0x4d, 0xf8, 0x76, 0x02, 0x44, 0x94, 0xcf, 0x32, 0xfe, 0xce, 0x3b, 0x5d, 0x2c, 0x89, 0x5f, 0xdc,
	0xd2, 0x9c, 0x6a, 0xec, 0x18, 0x6d, 0x0e, 0x86, 0xff, 0x5e, 0x9e, 0xee, 0x11, 0xd0, 0x49, 0x52,
	0x4e, 0x61, 0x90, 0x0d, 0xc3, 0x39, 0x15, 0x83, 0xb5, 0x62, 0x3f, 0x70, 0x7c, 0xad, 0x20, 0xbf,
	0x2e, 0x08, 0x1d, 0xf9, 0xb6, 0xa6, 0x64, 0x07, 0x82, 0x38, 0x98, 0x3a, 0x9f, 0xde, 0xbc, 0xd9,
};

const UINT8 kof2000_address_8_15_xor2[256] =
{
	0xb7, 0x45, 0x82, 0x5e, 0xa3, 0xab, 0xf8, 0x46, 0x21, 0xbd, 0xbb, 0x1f, 0xe3, 0x52, 0x29, 0xf0,
	0x2a, 0x9a, 0x2d, 0x8b, 0x0d, 0xca, 0x6b, 0x4c, 0x94, 0xcc, 0xba, 0x23, 0x1e, 0x44, 0x86, 0x2b,
	0xd9, 0x96, 0x33, 0x77, 0x14, 0xf3, 0x20, 0x35, 0x34, 0x4a, 0x8c, 0xc1, 0x2c, 0x22, 0x8a, 0x7e,
	0xa9, 0x39, 0xf1, 0x18, 0x91, 0x12, 0xd4, 0xee, 0x9d, 0x1a, 0x48, 0xce, 0xdb, 0x07, 0x5d, 0xe9,
	0x9b, 0xe0, 0xdf, 0x9e, 0x05, 0x71, 0x08, 0x6e, 0x73, 0xdd, 0x26, 0xe5, 0x32, 0x98, 0xa2, 0x87,
	0x4e, 0x78, 0x3b, 0x89, 0x3f, 0x0a, 0x84, 0x93, 0xfa, 0x42, 0x15, 0xf2, 0x00, 0xbe, 0x06, 0x5a,
	0x67, 0xf7, 0x54, 0x92, 0x36, 0x0b, 0xb5, 0xc2, 0x24, 0x41, 0x68, 0xd0, 0xb0, 0x47, 0x9c, 0x7a,
	0xed, 0xb9, 0x3e, 0x13, 0xa7, 0x6d, 0x1b, 0x95, 0xb2, 0xc0, 0xc3, 0xbf, 0xfc, 0x83, 0x81, 0xef,
	0xb4, 0xb8, 0xa0, 0xae, 0xe8, 0x61, 0xdc, 0xd2, 0xc5, 0x4d, 0xf5, 0x3c, 0x88, 0x97, 0xd3, 0xf6,
	0x31, 0x11, 0x30, 0xfb, 0x6a, 0x03, 0x04, 0xd1, 0x37, 0xa5, 0x28, 0xe4, 0xeb, 0x1c, 0x01, 0x65,
	0x57, 0x62, 0xfd, 0x58, 0xda, 0x74, 0xb6, 0x72, 0x8d, 0x4f, 0xe6, 0x64, 0xe2, 0xc9, 0xaa, 0x4b,
	0xec, 0xd7, 0xe7, 0x50, 0xaf, 0x59, 0xf4, 0xe1, 0xfe, 0xcf, 0x53, 0x63, 0x16, 0x25, 0x02, 0x09,
	0x6c, 0x40, 0xcd, 0x43, 0x2f, 0xde, 0x60, 0x55, 0xb1, 0x2e, 0xd8, 0xbc, 0x56, 0xa6, 0x3d, 0x1d,
	0xb3, 0x17, 0xd6, 0x99, 0xac, 0x75, 0xc7, 0x0c, 0xc6, 0xd5, 0xa1, 0x5b, 0x9f, 0x76, 0x7c, 0x90,
	0x49, 0x85, 0x69, 0x7f, 0x6f, 0x8f, 0x10, 0xf9, 0x5c, 0x19, 0x0f, 0x80, 0x27, 0x7b, 0x70, 0x8e,
	0x7d, 0xa4, 0x3a, 0xea, 0xc4, 0x66, 0xcb, 0xa8, 0x51, 0xc8, 0x0e, 0x5f, 0xff, 0xad, 0x38, 0x79,
};

const UINT8 kof2000_address_16_23_xor1[256] =
{
	0xa5, 0x12, 0x0e, 0x54, 0x1a, 0xfb, 0x9d, 0x8a, 0xc3, 0xd0, 0x5a, 0xdb, 0xe9, 0xa3, 0x85, 0x78,
	0xb1, 0xfe, 0x42, 0xf3, 0x0b, 0x2b, 0xe2, 0xf0, 0x46, 0x07, 0x80, 0x58, 0x2c, 0xaa, 0x70, 0x3d,
	0xc8, 0xbe, 0x5c, 0xa4, 0xe8, 0x81, 0x50, 0x47, 0x6b, 0xbb, 0xa8, 0xcc, 0xc6, 0x49, 0x62, 0xb6,
	0x40, 0xe5, 0x9e, 0x22, 0x02, 0x9c, 0x4a, 0x24, 0x25, 0x5b, 0x4b, 0x17, 0x8f, 0xc5, 0x6c, 0xae,
	0x99, 0x90, 0x91, 0xfc, 0x65, 0xd7, 0xf2, 0x93, 0x8c, 0x27, 0x14, 0xeb, 0xee, 0xcd, 0x8d, 0x48,
	0xc0, 0x8e, 0xa2, 0x32, 0xda, 0xb5, 0x0d, 0xb8, 0x28, 0xbc, 0x5e, 0x6d, 0x45, 0x9f, 0x6e, 0x2f,
	0x03, 0xd8, 0x86, 0xdc, 0xa7, 0x8b, 0xa6, 0xbf, 0xd2, 0x41, 0xa0, 0x7e, 0x4e, 0x36, 0x5d, 0x44,
	0x88, 0x79, 0x73, 0xab, 0x33, 0x39, 0xc7, 0x1f, 0x3f, 0x26, 0xde, 0x72, 0x5f, 0xcb, 0xfa, 0x75,
	0x87, 0x23, 0x63, 0x7c, 0x4c, 0x04, 0x84, 0x3c, 0x06, 0x76, 0xb3, 0x05, 0xe0, 0xce, 0xf9, 0xd5,
	0x97, 0x95, 0xb7, 0x3b, 0xdd, 0x29, 0xc2, 0xf8, 0x67, 0x35, 0xba, 0x61, 0x1c, 0x3e, 0x0f, 0x0a,
	0xb0, 0xef, 0x00, 0x57, 0xc4, 0xb9, 0x55, 0x51, 0x38, 0x20, 0xfd, 0xad, 0xdf, 0x83, 0x74, 0xf5,
	0x10, 0xff, 0x43, 0x2e, 0x2a, 0x66, 0xf1, 0x11, 0x96, 0x1b, 0xd1, 0xec, 0x53, 0x56, 0xe1, 0x7d,
	0x9b, 0x7f, 0xa9, 0x77, 0x08, 0xe3, 0xb2, 0x4d, 0x6f, 0x16, 0x98, 0x1e, 0x21, 0x69, 0x19, 0x1d,
	0x37, 0x13, 0x2d, 0xaf, 0x7a, 0xa1, 0xea, 0x31, 0x9a, 0xcf, 0xe4, 0x59, 0xd6, 0x94, 0x4f, 0x7b,
	0x92, 0xf7, 0x30, 0xe6, 0xe7, 0x82, 0xc1, 0x0c, 0x89, 0x52, 0x68, 0x71, 0xb4, 0x3a, 0x15, 0xac,
	0x01, 0xf4, 0xf6, 0x64, 0x18, 0x60, 0xc9, 0x6a, 0x34, 0xd3, 0xca, 0x09, 0xed, 0xbd, 0xd4, 0xd9,
};

const UINT8 kof2000_address_16_23_xor2[256] =
{
	0x00, 0xb8, 0xf0, 0x34, 0xca, 0x21, 0x3c, 0xf9, 0x01, 0x8e, 0x75, 0x70, 0xec, 0x13, 0x27, 0x96,
	0xf4, 0x5b, 0x88, 0x1f, 0xeb, 0x4a, 0x7d, 0x9d, 0xbe, 0x02, 0x14, 0xaf, 0xa2, 0x06, 0xc6, 0xdb,
	0x35, 0x6b, 0x74, 0x45, 0x7b, 0x29, 0xd2, 0xfe, 0xb6, 0x15, 0xd0, 0x8a, 0xa9, 0x2d, 0x19, 0xf6,
	0x5e, 0x5a, 0x90, 0xe9, 0x11, 0x33, 0xc2, 0x47, 0x37, 0x4c, 0x4f, 0x59, 0xc3, 0x04, 0x57, 0x1d,
	0xf2, 0x63, 0x6d, 0x6e, 0x31, 0x95, 0xcb, 0x3e, 0x67, 0xb2, 0xe3, 0x98, 0xed, 0x8d, 0xe6, 0xfb,
	0xf8, 0xba, 0x5d, 0xd4, 0x2a, 0xf5, 0x3b, 0x82, 0x05, 0x16, 0x44, 0xef, 0x4d, 0xe7, 0x93, 0xda,
	0x9f, 0xbb, 0x61, 0xc9, 0x53, 0xbd, 0x76, 0x78, 0x52, 0x36, 0x0c, 0x66, 0xc1, 0x10, 0xdd, 0x7a,
	0x84, 0x69, 0xcd, 0xfd, 0x58, 0x0d, 0x6c, 0x89, 0x68, 0xad, 0x3a, 0xb0, 0x4b, 0x46, 0xc5, 0x03,
	0xb4, 0xf7, 0x30, 0x8c, 0x4e, 0x60, 0x73, 0xa1, 0x8b, 0xb1, 0x62, 0xcc, 0xd1, 0x08, 0xfc, 0x77,
	0x7e, 0xcf, 0x56, 0x51, 0x07, 0xa6, 0x80, 0x92, 0xdc, 0x0b, 0xa4, 0xc7, 0xe8, 0xe1, 0xb5, 0x71,
	0xea, 0xb3, 0x2f, 0x94, 0x18, 0xe2, 0x3d, 0x49, 0x65, 0xaa, 0xf1, 0x91, 0xc8, 0x99, 0x55, 0x79,
	0x86, 0xa7, 0x26, 0xa0, 0xac, 0x5f, 0xce, 0x6a, 0x5c, 0xf3, 0x87, 0x8f, 0x12, 0x1c, 0xd8, 0xe4,
	0x9b, 0x64, 0x2e, 0x1e, 0xd7, 0xc0, 0x17, 0xbc, 0xa3, 0xa8, 0x9a, 0x0e, 0x25, 0x40, 0x41, 0x50,
	0xb9, 0xbf, 0x28, 0xdf, 0x32, 0x54, 0x9e, 0x48, 0xd5, 0x2b, 0x42, 0xfa, 0x9c, 0x7f, 0xd3, 0x85,
	0x43, 0xde, 0x81, 0x0f, 0x24, 0xc4, 0x38, 0xae, 0x83, 0x1b, 0x6f, 0x7c, 0xe5, 0xff, 0x1a, 0xd9,
	0x3f, 0xb7, 0x22, 0x97, 0x09, 0xe0, 0xa5, 0x20, 0x23, 0x2c, 0x72, 0xd6, 0x39, 0xab, 0x0a, 0xee,
};

const UINT8 kof2000_address_0_7_xor[256] =
{
	0x7a, 0x14, 0x5a, 0xc7, 0x7d, 0xf5, 0x47, 0x2a, 0x95, 0xa4, 0xe8, 0x3b, 0xb8, 0xa3, 0xc5, 0xab,
	0x49, 0xc2, 0x3e, 0x5c, 0x2e, 0x11, 0xfc, 0x13, 0x5e, 0xad, 0xb6, 0xb3, 0x57, 0xaf, 0xb7, 0xfa,
	0xcf, 0x24, 0x33, 0x20, 0x86, 0x88, 0x27, 0x59, 0xb5, 0x9a, 0x8a, 0x87, 0x0c, 0x92, 0x8e, 0x5d,
	0xe9, 0xb4, 0xbc, 0x76, 0x54, 0x46, 0xe4, 0xbf, 0xa5, 0xed, 0xa8, 0xd7, 0x65, 0x71, 0xd9, 0xc0,
	0x09, 0x2f, 0x3f, 0x1c, 0x64, 0xca, 0x80, 0xff, 0xfe, 0xfd, 0x79, 0x3a, 0x31, 0x0a, 0xd2, 0x4c,
	0x53, 0x6d, 0x40, 0xa9, 0x74, 0x2b, 0x56, 0x8d, 0x29, 0x68, 0xf8, 0xa2, 0x21, 0x5b, 0x0d, 0x25,
	0x1d, 0xcc, 0x7e, 0x69, 0x4e, 0xe7, 0x98, 0x96, 0xee, 0x43, 0x97, 0x94, 0xf0, 0x81, 0x8c, 0x51,
	0xa0, 0x99, 0xc1, 0x48, 0xe0, 0xdf, 0x85, 0x04, 0x9e, 0x6c, 0xc6, 0x36, 0x9c, 0x50, 0xf1, 0xaa,
	0x01, 0x28, 0x23, 0x73, 0xe1, 0x41, 0x1b, 0x89, 0xba, 0xd5, 0x93, 0xeb, 0x8f, 0x05, 0x6a, 0xc4,
	0xac, 0xa7, 0x60, 0xae, 0x63, 0xfb, 0x44, 0xde, 0x1e, 0x00, 0xf7, 0xe6, 0x82, 0x0e, 0x55, 0xcd,
	0xf6, 0x3d, 0xb0, 0x8b, 0xc9, 0x7f, 0x91, 0xdc, 0xf9, 0x34, 0x3c, 0x7b, 0x2d, 0xbd, 0x70, 0x72,
	0xd1, 0x77, 0x0b, 0x39, 0xe3, 0x9d, 0x45, 0x9b, 0x15, 0x38, 0xd4, 0x16, 0x90, 0x7c, 0x12, 0x84,
	0x67, 0x10, 0x4f, 0x03, 0xc3, 0xe2, 0x02, 0x32, 0xa1, 0xbe, 0xa6, 0x08, 0x6b, 0x52, 0x4a, 0x26,
	0x30, 0x6f, 0xef, 0x2c, 0xd8, 0x22, 0x9f, 0x58, 0xec, 0xf2, 0xe5, 0xdd, 0x5f, 0x75, 0x83, 0x1a,
	0xb9, 0x35, 0xbb, 0x78, 0xce, 0x06, 0x17, 0x07, 0xc8, 0x4d, 0x66, 0x61, 0xdb, 0xb1, 0xcb, 0xea,
	0x6e, 0x62, 0x19, 0xf3, 0x42, 0x1f, 0x18, 0xd0, 0x0f, 0xda, 0x37, 0xb2, 0xf4, 0xd6, 0xd3, 0x4b,
};





void NeoCMCExtractSData(UINT8* rom, UINT8* sdata, INT32 rom_size, INT32 sdata_size)
{
#if 0
	/* the S data comes from the end fo the C data */
	rom += rom_size - sdata_size;

	for (INT32 i = 0; i < sdata_size; i++) {
		sdata[i] = rom[(i & ~0x1F) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4)];
	}
#endif
	INT32 i;
	// the S data comes from the end fo the C data
	if (sdata_size == 0x100000) {
		// 1 MB of data, special for kf2k3pcb
		rom += rom_size - sdata_size /2;
		for (i = 0; i < sdata_size / 2; i++) {
			sdata[i + 0] = rom[(i & ~0x1F) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4) - 0x1000000 ];
			sdata[i + sdata_size / 2] = rom[(i & ~0x1F) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4)];
 		}
	} else {
		// Normal data extraction
 		rom += rom_size - sdata_size;
		for (i = 0; i < sdata_size; i++) {
			sdata[i] = rom[(i & ~0x1F) + ((i & 7) << 2) + ((~i & 8) >> 2) + ((i & 0x10) >> 4)];
 		}
	}
}

inline static void cmc_xor(UINT8 *r0, UINT8 *r1,
		    const UINT8 *table0hi,
		    const UINT8 *table0lo,
		    const UINT8 *table1,
		    INT32 base,
		    INT32 invert)

{
	UINT8 c0, c1, tmp, xor0, xor1;

	tmp = table1[(base & 0xff) ^ address_0_7_xor[(base >> 8) & 0xff]];
	xor0 = (table0hi[(base >> 8) & 0xff] & 0xfe) | (tmp & 0x01);
	xor1 = (tmp & 0xfe) | (table0lo[(base >> 8) & 0xff] & 0x01);

    c0 = *r0;
    c1 = *r1;

	if (invert)	{
		*r0 = c1 ^ xor0;
		*r1 = c0 ^ xor1;
	} else {
		*r0 = c0 ^ xor0;
		*r1 = c1 ^ xor1;
	}
}

void NeoCMCDecrypt(UINT8 extra_xor, UINT8* rom, UINT8* buf, INT32 offset, INT32 block_size, INT32 rom_size)
{
	INT32 clamp_size, rpos;

	if (rom_size > 0x04000000) rom_size = 0x04000000;

	// Adjust variables for addressing 32bit words
	rom_size   >>= 2;
	block_size >>= 2;
	offset     >>= 2;

	// special handling for games with 6 C ROMs
	for (clamp_size = 1 << 30; clamp_size > rom_size; clamp_size >>= 1) { }

	// Data xor
	for (rpos = 0; rpos < block_size; rpos++)
	{
		cmc_xor(buf+4*rpos+0, buf+4*rpos+3, type0_t03, type0_t12, type1_t03, rpos, (rpos>>8) & 1);
		cmc_xor(buf+4*rpos+1, buf+4*rpos+2, type0_t12, type0_t03, type1_t12, rpos, (((rpos + offset)>>16) ^ address_16_23_xor2[(rpos>>8) & 0xff]) & 1);
	}

	// Address xor
	for (rpos = 0; rpos < block_size; rpos++)
	{
		INT32 baser = rpos + offset;

		baser ^= address_0_7_xor[(baser >> 8) & 0xff];
		baser ^= address_16_23_xor2[(baser >> 8) & 0xff] << 16;
		baser ^= address_16_23_xor1[baser & 0xff] << 16;

		if (rpos + offset < clamp_size)
			baser &= clamp_size - 1;
		else
			baser = clamp_size + (baser & ((clamp_size >> 1) - 1));

		baser ^= address_8_15_xor2[baser & 0xff] << 8;
		baser ^= address_8_15_xor1[(baser >> 16) & 0xff] << 8;

		baser ^= extra_xor;

		((UINT32*)rom)[baser] = ((UINT32*)buf)[rpos];
	}
}

static UINT8 NeoCMCGetXorData(UINT8 *src, UINT8 address_bits, UINT8 address_xor)
{
	UINT16 address;
	
	address  = ((src[0xf9a0 + address_bits] << 0) | (src[0xf9a0 + address_bits + 1] << 8));
	address ^= ((src[0xf9a0 + address_xor ] << 8) | (src[0xf9a0 + address_xor  + 1] << 0));
	address  = ((address & 0x8000) >> 15) | ((address & 0x7fff) << 1);
	
	return src[address];
}

static void NeoCMCGetExtraXor()
{
	// Chip  -- Calculated val -OLDXOR- 
	// CMC42 -- 02, 03, 4d, 68 -- f8 -- Bang Bead
	// CMC42 -- 02, fc, 4d, 68 -- 07 -- Ganryu
	// CMC42 -- 33, fd, 4d, 68 -- 06 -- Garou - Mark of the Wolves
	// CMC42 -- 33, 56, 4d, 68 -- ad -- Metal Slug 3
	// CMC42 -- 02, 04, 4d, 68 -- ff -- Nightmare in the Dark
	// CMC42 -- 22, 64, 4d, 68 -- 9f -- Prehistoric Isle 2
	// CMC42 -- 12, 05, 4d, 68 -- fe -- Sengoku 3
	// CMC42 -- 32, fe, 4d, 68 -- 05 -- Strikers 1945 Plus
	// CMC42 -- 32, fb, 4d, 68 -- 00 -- The King of Fighters '99
	// CMC42 -- 02, 46, 4d, 68 -- bd -- Zupapa!
	// CMC50 -- 02, f0, 2b, a9 -- ac -- Jockey Grand Prix
	// CMC50 -- 3a, 36, 2b, a9 -- 6a -- Matrimelee
	// CMC50 -- 23, 6d, 2b, a9 -- 31 -- Metal Slug 4
	// CMC50 -- 32, 45, 2b, a9 -- 19 -- Metal Slug 5
	// CMC50 -- 02, 72, 2b, a9 -- 2e -- Pochi and Nyaa
	// CMC50 -- 32, 63, 2b, a9 -- 3f -- Rage of the Dragons
	// CMC50 -- 32, 53, 2b, a9 -- 0f -- Samurai Shodown V
	// CMC50 -- 32, 51, 2b, a9 -- 0d -- Samurai Shodown V Special
	// CMC50 -- 3a, 0b, 2b, a9 -- 57 -- SNK vs. Capcom - SVC Chaos
	// CMC50 -- 3a, 5c, 2b, a9 -- 00 -- The King of Fighters 2000
	// CMC50 -- 32, 42, 2b, a9 -- 1e -- The King of Fighters 2001
	// CMC50 -- 32, b0, 2b, a9 -- ec -- The King of Fighters 2002
	// CMC50 -- 3a, c1, 2b, a9 -- 9d -- The King of Fighters 2003

	// Note that the OLD XOR for CMC50 is ^ 0x5c or CMC42 is ^ 0xfb to match corrected value.

//	INT32 nFlags, nUnknown1, nUnknown2;

	// flags:
	//  00110000 - total sprite data size - (30 = 64Mb, 20 = 48Mb, 10 = 32Mb, 00 = 16Mb)
	//  00001000 - alternate FIX banking? - King of Fighters 2000, King of Fighters 2000, Matrimelee, and SVC
	//  00000010 - always set - unknown purpose
	//  00000001 - FIX banking? - Garou, Metal Slug 3, and Metal Slug 4
	// unknown1: must be 4d (CMC42) or 2b (CMC50)
	// unknown2: must be 68 (CMC42) or a9 (CMC50)

//	nFlags 				= NeoCMCGetXorData(NeoZ80ROMActive,0x16,0x0a) ^ NeoCMCGetXorData(NeoZ80ROMActive,0x1e,0x1c);
	nNeoProtectionXor	= NeoCMCGetXorData(NeoZ80ROMActive,0x10,0x04) ^ NeoCMCGetXorData(NeoZ80ROMActive,0x1a,0x18);
//	nUnknown1			= NeoCMCGetXorData(NeoZ80ROMActive,0x0c,0x00) ^ NeoCMCGetXorData(NeoZ80ROMActive,0x0e,0x06);
//	nUnknown2			= NeoCMCGetXorData(NeoZ80ROMActive,0x12,0x02) ^ NeoCMCGetXorData(NeoZ80ROMActive,0x14,0x08);
}

/* CMC42 protection chip */
void NeoCMC42Init()
{
	type0_t03 =          kof99_type0_t03;
	type0_t12 =          kof99_type0_t12;
	type1_t03 =          kof99_type1_t03;
	type1_t12 =          kof99_type1_t12;
	address_8_15_xor1 =  kof99_address_8_15_xor1;
	address_8_15_xor2 =  kof99_address_8_15_xor2;
	address_16_23_xor1 = kof99_address_16_23_xor1;
	address_16_23_xor2 = kof99_address_16_23_xor2;
	address_0_7_xor =    kof99_address_0_7_xor;

	// allow skipping calculating xor for bootlegs/hacks
	if (nNeoProtectionXor == -1)
		NeoCMCGetExtraXor(); 
	else
		nNeoProtectionXor ^= 0xfb;
}

/* CMC50 protection chip */
void NeoCMC50Init()
{
	type0_t03 =          kof2000_type0_t03;
	type0_t12 =          kof2000_type0_t12;
	type1_t03 =          kof2000_type1_t03;
	type1_t12 =          kof2000_type1_t12;
	address_8_15_xor1 =  kof2000_address_8_15_xor1;
	address_8_15_xor2 =  kof2000_address_8_15_xor2;
	address_16_23_xor1 = kof2000_address_16_23_xor1;
	address_16_23_xor2 = kof2000_address_16_23_xor2;
	address_0_7_xor =    kof2000_address_0_7_xor;

	// allow skipping calculating xor for bootlegs/hacks
	if (nNeoProtectionXor == -1)
		NeoCMCGetExtraXor(); 
	else
		nNeoProtectionXor ^= 0x5c;
}

// M1 Decryption
static const UINT8 m1_address_8_15_xor[256] = {
        0x0a, 0x72, 0xb7, 0xaf, 0x67, 0xde, 0x1d, 0xb1, 0x78, 0xc4, 0x4f, 0xb5, 0x4b, 0x18, 0x76, 0xdd,
        0x11, 0xe2, 0x36, 0xa1, 0x82, 0x03, 0x98, 0xa0, 0x10, 0x5f, 0x3f, 0xd6, 0x1f, 0x90, 0x6a, 0x0b,
        0x70, 0xe0, 0x64, 0xcb, 0x9f, 0x38, 0x8b, 0x53, 0x04, 0xca, 0xf8, 0xd0, 0x07, 0x68, 0x56, 0x32,
        0xae, 0x1c, 0x2e, 0x48, 0x63, 0x92, 0x9a, 0x9c, 0x44, 0x85, 0x41, 0x40, 0x09, 0xc0, 0xc8, 0xbf,
        0xea, 0xbb, 0xf7, 0x2d, 0x99, 0x21, 0xf6, 0xba, 0x15, 0xce, 0xab, 0xb0, 0x2a, 0x60, 0xbc, 0xf1,
        0xf0, 0x9e, 0xd5, 0x97, 0xd8, 0x4e, 0x14, 0x9d, 0x42, 0x4d, 0x2c, 0x5c, 0x2b, 0xa6, 0xe1, 0xa7,
        0xef, 0x25, 0x33, 0x7a, 0xeb, 0xe7, 0x1b, 0x6d, 0x4c, 0x52, 0x26, 0x62, 0xb6, 0x35, 0xbe, 0x80,
        0x01, 0xbd, 0xfd, 0x37, 0xf9, 0x47, 0x55, 0x71, 0xb4, 0xf2, 0xff, 0x27, 0xfa, 0x23, 0xc9, 0x83,
        0x17, 0x39, 0x13, 0x0d, 0xc7, 0x86, 0x16, 0xec, 0x49, 0x6f, 0xfe, 0x34, 0x05, 0x8f, 0x00, 0xe6,
        0xa4, 0xda, 0x7b, 0xc1, 0xf3, 0xf4, 0xd9, 0x75, 0x28, 0x66, 0x87, 0xa8, 0x45, 0x6c, 0x20, 0xe9,
        0x77, 0x93, 0x7e, 0x3c, 0x1e, 0x74, 0xf5, 0x8c, 0x3e, 0x94, 0xd4, 0xc2, 0x5a, 0x06, 0x0e, 0xe8,
        0x3d, 0xa9, 0xb2, 0xe3, 0xe4, 0x22, 0xcf, 0x24, 0x8e, 0x6b, 0x8a, 0x8d, 0x84, 0x4a, 0xd2, 0x91,
        0x88, 0x79, 0x57, 0xa5, 0x0f, 0xcd, 0xb9, 0xac, 0x3b, 0xaa, 0xb3, 0xd1, 0xee, 0x31, 0x81, 0x7c,
        0xd7, 0x89, 0xd3, 0x96, 0x43, 0xc5, 0xc6, 0xc3, 0x69, 0x7f, 0x46, 0xdf, 0x30, 0x5b, 0x6e, 0xe5,
        0x08, 0x95, 0x9b, 0xfb, 0xb8, 0x58, 0x0c, 0x61, 0x50, 0x5d, 0x3a, 0xa2, 0x29, 0x12, 0xfc, 0x51,
        0x7d, 0x1a, 0x02, 0x65, 0x54, 0x5e, 0x19, 0xcc, 0xdc, 0xdb, 0x73, 0xed, 0xad, 0x59, 0x2f, 0xa3,
};

static const UINT8 m1_address_0_7_xor[256] = {
        0xf4, 0xbc, 0x02, 0xf7, 0x2c, 0x3d, 0xe8, 0xd9, 0x50, 0x62, 0xec, 0xbd, 0x53, 0x73, 0x79, 0x61,
        0x00, 0x34, 0xcf, 0xa2, 0x63, 0x28, 0x90, 0xaf, 0x44, 0x3b, 0xc5, 0x8d, 0x3a, 0x46, 0x07, 0x70,
        0x66, 0xbe, 0xd8, 0x8b, 0xe9, 0xa0, 0x4b, 0x98, 0xdc, 0xdf, 0xe2, 0x16, 0x74, 0xf1, 0x37, 0xf5,
        0xb7, 0x21, 0x81, 0x01, 0x1c, 0x1b, 0x94, 0x36, 0x09, 0xa1, 0x4a, 0x91, 0x30, 0x92, 0x9b, 0x9a,
        0x29, 0xb1, 0x38, 0x4d, 0x55, 0xf2, 0x56, 0x18, 0x24, 0x47, 0x9d, 0x3f, 0x80, 0x1f, 0x22, 0xa4,
        0x11, 0x54, 0x84, 0x0d, 0x25, 0x48, 0xee, 0xc6, 0x59, 0x15, 0x03, 0x7a, 0xfd, 0x6c, 0xc3, 0x33,
        0x5b, 0xc4, 0x7b, 0x5a, 0x05, 0x7f, 0xa6, 0x40, 0xa9, 0x5d, 0x41, 0x8a, 0x96, 0x52, 0xd3, 0xf0,
        0xab, 0x72, 0x10, 0x88, 0x6f, 0x95, 0x7c, 0xa8, 0xcd, 0x9c, 0x5f, 0x32, 0xae, 0x85, 0x39, 0xac,
        0xe5, 0xd7, 0xfb, 0xd4, 0x08, 0x23, 0x19, 0x65, 0x6b, 0xa7, 0x93, 0xbb, 0x2b, 0xbf, 0xb8, 0x35,
        0xd0, 0x06, 0x26, 0x68, 0x3e, 0xdd, 0xb9, 0x69, 0x2a, 0xb2, 0xde, 0x87, 0x45, 0x58, 0xff, 0x3c,
        0x9e, 0x7d, 0xda, 0xed, 0x49, 0x8c, 0x14, 0x8e, 0x75, 0x2f, 0xe0, 0x6e, 0x78, 0x6d, 0x20, 0xd2,
        0xfa, 0x2d, 0x51, 0xcc, 0xc7, 0xe7, 0x1d, 0x27, 0x97, 0xfc, 0x31, 0xdb, 0xf8, 0x42, 0xe3, 0x99,
        0x5e, 0x83, 0x0e, 0xb4, 0x2e, 0xf6, 0xc0, 0x0c, 0x4c, 0x57, 0xb6, 0x64, 0x0a, 0x17, 0xa3, 0xc1,
        0x77, 0x12, 0xfe, 0xe6, 0x8f, 0x13, 0x71, 0xe4, 0xf9, 0xad, 0x9f, 0xce, 0xd5, 0x89, 0x7e, 0x0f,
        0xc2, 0x86, 0xf3, 0x67, 0xba, 0x60, 0x43, 0xc9, 0x04, 0xb3, 0xb0, 0x1e, 0xb5, 0xc8, 0xeb, 0xa5,
        0x76, 0xea, 0x5c, 0x82, 0x1a, 0x4f, 0xaa, 0xca, 0xe1, 0x0b, 0x4e, 0xcb, 0x6a, 0xef, 0xd1, 0xd6,
};

static UINT16 generate_cs16(UINT8 *rom, INT32 size)
{
    UINT16 cs16;
    cs16 = 0x0000;
    for (INT32 i = 0; i < size; i++) {
        cs16 += rom[i];
    }
    return cs16 & 0xffff;
}

static INT32 m1_address_scramble(INT32 address, UINT16 key)
{
	INT32 block;
	INT32 aux;

	const INT32 p1[8][16] = {
		{15, 14, 10,  7,  1,  2,  3,  8,  0, 12, 11, 13,  6,  9,  5,  4},
		{ 7,  1,  8, 11, 15,  9,  2,  3,  5, 13,  4, 14, 10,  0,  6, 12},
		{ 8,  6, 14,  3, 10,  7, 15,  1,  4,  0,  2,  5, 13, 11, 12,  9},
		{ 2,  8, 15,  9,  3,  4, 11,  7, 13,  6,  0, 10,  1, 12, 14,  5},
		{ 1, 13,  6, 15, 14,  3,  8, 10,  9,  4,  7, 12,  5,  2,  0, 11},
		{11, 15,  3,  4,  7,  0,  9,  2,  6, 14, 12,  1,  8,  5, 10, 13},
		{10,  5, 13,  8,  6, 15,  1, 14, 11,  9,  3,  0, 12,  7,  4,  2},
		{ 9,  3,  7,  0,  2, 12,  4, 11, 14, 10,  5,  8, 15, 13,  1,  6},
	};

	block = (address >> 16) & 7;
	aux = address & 0xffff;

        aux ^= BITSWAP16(key, 12, 0, 2, 4, 8, 15, 7, 13, 10, 1, 3, 6, 11, 9, 14, 5);
	aux = BITSWAP16(aux,
		p1[block][15], p1[block][14], p1[block][13], p1[block][12],
		p1[block][11], p1[block][10], p1[block][9] , p1[block][8],
		p1[block][7] , p1[block][6] , p1[block][5] , p1[block][4],
		p1[block][3] , p1[block][2] , p1[block][1] , p1[block][0]);
        aux ^= m1_address_0_7_xor[(aux >> 8) & 0xff];
	aux ^= m1_address_8_15_xor[aux & 0xff] << 8;
	aux = BITSWAP16(aux, 7, 15, 14, 6, 5, 13, 12, 4, 11, 3, 10, 2, 9, 1, 8, 0);

	return (block << 16) | aux;
}

void neogeo_cmc50_m1_decrypt()
{
	UINT8 *rom = NeoZ80ROMActive;
	UINT8 *buffer = (UINT8*)BurnMalloc(0x80000);
	
	UINT16 key = generate_cs16(rom, 0x10000);

	for (INT32 i = 0; i < 0x80000; i++) { 
		buffer[i] = rom[m1_address_scramble(i, key)];
	}

	memcpy(rom, buffer, 0x80000);
	BurnFree(buffer);
}
